%{
  import java.io.*;
%}
      
%token NL          /* newline  */
%token <sval> COMMENTS
%token <sval> BUY /* grammar keywords */
%token <sval> SELL
%token <sval> SELECT
%token <sval> BUYSEC
%token <sval> SELLSEC
%token <sval> USERSEC
%token <sval> PRINT
%token <sval> TF
%token <sval> RETURN
%token <sval> CONTINUE
%token <sval> BREAK
%token <sval> WHILE
%token <sval> FOR
%token <sval> IF
%token <sval> ELSE
%token <sval> SECTOR /* domain specific keywords */
%token <sval> VOLUME
%token <sval> PROFIT
%token <sval> LOSS
%token <sval> RISE
%token <sval> FALL
%token <sval> PRICE
%token <sval> ALL
%token <ival> INTEGER
%token <dval> NUM
%token <dval> PERCENT
%token <sval> LITSTRING /* literal string */
%token <sval> LOGICAL   /* logical operators */
%token <sval> NOT       /* logical not */
%token <sval> EQ
%token <sval> LEQ
%token <sval> GEQ
%token <sval> NEQ
%token <sval> PLUSPLUS
%token <sval> MINUSMINUS
%token <sval> PLUSEQ
%token <sval> MINUSEQ
%token <sval> MULEQ
%token <sval> DIVEQ
%token <sval> POWEQ
%token <sval> CROSSOP
%token <sval> CAPIDENT
%token <sval> IDENT
%token <sval> TYPE

/* Terminals used in the user-defined section */
%type <sval> RETURN
%type <sval> CONTINUE
%type <sval> BREAK
%type <sval> WHILE
%type <sval> FOR
%type <sval> IF
%type <sval> ELSE
%type <sval> PLUSPLUS
%type <sval> MINUSMINUS
%type <sval> PLUSEQ
%type <sval> MINUSEQ
%type <sval> MULEQ
%type <sval> DIVEQ
%type <sval> POWEQ

%type <node> filter
%type <node> statement
%type <node> prog
%type <node> linestat
%type <node> strategy
%type <node> select
%type <node> print
%type <node> exp
%type <node> number
%type <node> list
%type <node> object
%type <node> identifier
%type <node> predefined_id
%type <node> indicator
%type <node> function
%type <node> cond
%type <sval> compare
%type <node> action

/* Non-terminals used in the user-defined section */
%type <node> user_defined
%type <node> userfunctions
%type <node> userfunc
%type <node> signature
%type <node> args
%type <node> argument
%type <node> block
%type <node> block_body
%type <node> func_statement
%type <node> if_group
%type <node> if_elif_else
%type <node> if_elif
%type <node> if
%type <node> else_if
%type <node> else
%type <node> while
%type <node> for
%type <node> for_condition
%type <node> for_cond_sec1
%type <node> for_cond_sec2
%type <node> assignment
%type <node> normal_assign
%type <node> special_assign
%type <node> special_assign1
%type <node> special_assign2
%type <sval> self_assign_operator
%type <node> func_keyword_statement
%type <sval> arith_operator
%type <node> return
%type <node> expression
%type <node> single_cond
%type <node> expr
%type <node> atom

%right '='         /* assignment */
%left ','
%left LOGICAL      /* and/or */
%right NOT
%left EQ LEQ GEQ NEQ '<' '>'
%left CROSSOP
%left '-' '+'
%left '*' '/'
%right NEG         /* negation--unary minus */
%right '^'         /* exponentiation */
%left '.'

%%

prog: NL prog                   { $$ = $2; }
        | buysec strategy       { $$=root=new SyntaxTreeNode("PROG",SyntaxTreeNode.Type.PROG,lexer.getLineNumber()+1);
                                  $$.addChild($2);$2.SetType(SyntaxTreeNode.Type.BUYSTRAT);}
        | buysec strategy user_defined
                                { $$=root=new SyntaxTreeNode("PROG",SyntaxTreeNode.Type.PROG,lexer.getLineNumber()+1);
                                  $$.addChild($2);$2.SetType(SyntaxTreeNode.Type.BUYSTRAT);
                                  if ($3 != null) $$.addChild($3);}
        | buysec strategy sellsec strategy  
                                {$$=root=new SyntaxTreeNode("PROG",SyntaxTreeNode.Type.PROG,lexer.getLineNumber()+1);
                                  $2.SetType(SyntaxTreeNode.Type.BUYSTRAT);$$.addChild($2);
                                  $4.SetType(SyntaxTreeNode.Type.SELLSTRAT);$$.addChild($4);}
        | buysec strategy sellsec strategy user_defined
                                { $$=root=new SyntaxTreeNode("PROG",SyntaxTreeNode.Type.PROG,lexer.getLineNumber()+1);
                                  $2.SetType(SyntaxTreeNode.Type.BUYSTRAT);$$.addChild($2);
                                  $4.SetType(SyntaxTreeNode.Type.SELLSTRAT);$$.addChild($4);
                                  if ($5 != null) $$.addChild($5);}
        ;

buysec: BUYSEC NL
        ;

sellsec: SELLSEC NL
        ;

usersec: usersec NL
        | USERSEC NL
        ;

user_defined: usersec           { $$ = null; }
        | usersec userfunctions { $$ = $2;}
        ;

strategy: strategy linestat     { $$ = $1; if($2!=null){$$.addChild($2);} }
        | linestat              { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode("STRATEGY",SyntaxTreeNode.Type.NONE,lexer.getLineNumber()+1);
                                  if(tmp!=null){ $$.addChild(tmp);} }
        ;

linestat: NL                    { if (interactive) System.out.print("> "); }
        | statement NL          { $$ = $1; if (interactive) System.out.print("> "); }
        | COMMENTS NL           { System.out.println("Comments: " + $1); }
        ;

statement: print                { $$ = $1;}
        | filter                { $$ = $1;}
        | action                { $$ = $1;}
        ;

print: PRINT list               { $$=new SyntaxTreeNode("PRINT",SyntaxTreeNode.Type.PRINT,lexer.getLineNumber()+1);
                                  $$.addChild($2); }
        | PRINT                 { $$=new SyntaxTreeNode("PRINT",SyntaxTreeNode.Type.PRINT,lexer.getLineNumber()+1); }
        ;

filter: select                  { $$ = $1;}
        | cond                  { $$ = $1;}
        ;

select: SELECT list             { $$=new SyntaxTreeNode("SELECT",SyntaxTreeNode.Type.SELECT,lexer.getLineNumber()+1); $$.addChild($2); }
        | SELECT ALL            { $$=new SyntaxTreeNode("SELECT ALL", SyntaxTreeNode.Type.SELECT,lexer.getLineNumber()+1);}
        ;

userfunctions: userfunctions userfunc
                                { $$.addChild($2);}
        | userfunc              { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null,SyntaxTreeNode.Type.USERDEFINE,lexer.getLineNumber()+1);
                                  $$.addChild(tmp);}
        ;

userfunc: userfunc NL           { $$ = $1; }
        | signature block       { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode(null,SyntaxTreeNode.Type.USERFUNC,lexer.getLineNumber()+1);
                                  $$.addChild(tmp);$$.addChild($2);}
        ;

signature: TYPE IDENT '(' ')'   { $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.SIGNATURE, lexer.getLineNumber()+1);
                                  $$.addChild(new SyntaxTreeNode($1, SyntaxTreeNode.Type.TYPE, lexer.getLineNumber()+1));}
        | TYPE IDENT '(' args ')'
                                { $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.SIGNATURE, lexer.getLineNumber()+1);
                                  $$.addChild(new SyntaxTreeNode($1, SyntaxTreeNode.Type.TYPE, lexer.getLineNumber()+1));
                                  $$.addChild($4); }
        ;

args: args "," argument         { $1.addChild($3); $$ = $1; }
        | argument              { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.ARGS, lexer.getLineNumber()+1);
                                  $$.addChild(tmp); }
        ;

argument: TYPE IDENT            { SyntaxTreeNode t = new SyntaxTreeNode($1, SyntaxTreeNode.Type.TYPE, lexer.getLineNumber()+1);
                                  $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.ARGUMENT, lexer.getLineNumber()+1); 
                                  $$.addChild(t); }
        ; 

block: NL block                 { $$ = $2;}
        | '{' block_body '}'    { $$ = $2; }
        | '{' '}'               { $$ = new SyntaxTreeNode(null,SyntaxTreeNode.Type.BLOCK,lexer.getLineNumber()+1); }
        ;

block_body: NL block_body       { $$ = $2; }
        | func_statement NL block_body
                                { if ($1 != null){$3.addChildAtHead($1);} $$ = $3; }
        | func_statement NL     { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null,SyntaxTreeNode.Type.BLOCK,lexer.getLineNumber()+1);
                                  if (tmp != null) $$.addChild(tmp); }
        | func_statement        { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null,SyntaxTreeNode.Type.BLOCK,lexer.getLineNumber()+1);
                                  if (tmp != null) $$.addChild(tmp); }
        | NL                    { $$ = new SyntaxTreeNode(null,SyntaxTreeNode.Type.BLOCK,lexer.getLineNumber()+1); }
        ;

func_statement : COMMENTS       { $$ = null; }
        | expression            { $$ = $1; }
        | assignment            { $$ = $1; }
        | func_keyword_statement
                                { $$ = $1; }
        | if_group              { $$ = $1; }
        | while                 { $$ = $1; }
        | for                   { $$ = $1; }
        ;

assignment: normal_assign       { $$ = $1; }
        | special_assign        { $$ = $1; }
        ;

normal_assign: identifier '=' expression
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode('=', SyntaxTreeNode.Type.ASSIGN,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3); }
        | identifier '=' normal_assign
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode('=', SyntaxTreeNode.Type.ASSIGN,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3); }
        ;

special_assign: special_assign1 { $$ = $1; }
        | special_assign2       { $$ = $1; }
        ;

special_assign1: identifier PLUSPLUS
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode("++", SyntaxTreeNode.Type.ASSIGN,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); }
        | identifier MINUSMINUS { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode("--", SyntaxTreeNode.Type.ASSIGN,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); }
        ;

special_assign2: identifier self_assign_operator expression
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.ASSIGN,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3); }
        ;

self_assign_operator: PLUSEQ    { $$ = $1; }
        | MINUSEQ               { $$ = $1; }
        | MULEQ                 { $$ = $1; }
        | DIVEQ                 { $$ = $1; }
        | POWEQ                 { $$ = $1; }
        ;

if_group: if_elif_else          { $$ = $1; }
        | else_if               { $$ = $1; }
        | else                  { $$ = $1; }
        ;

if_elif_else: if_elif           { $$ = $1; }
        | if_elif else          { $1.addChild($2); $$ = $1;
                                  printDebug("if () {} else if {} else {}");}
        ;

if_elif: if_elif else_if        { $1.addChild($2); $$ = $1; printDebug("if () {} else if {}"); }
        | if                    { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.IFGROUP,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); }
        ;

if: IF '(' expression ')' block  { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.IF,lexer.getLineNumber()+1);
                                  $$.addChild($3); $$.addChild($5); }
        ;

else_if: ELSE IF '(' expression ')' block
                                { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.ELSEIF,lexer.getLineNumber()+1);
                                  $$.addChild($4); $$.addChild($6);
                                  printDebug("single line else if"); }
        ;

else:  ELSE block               { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.ELSE,lexer.getLineNumber()+1);
                                  $$.addChild($2); printDebug("single line else"); }
        ;

while: WHILE '(' expression ')' block
                                { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.WHILE,lexer.getLineNumber()+1);
                                  $$.addChild($3); $$.addChild($5); }
        ;

for: FOR '(' for_condition ')' block
                                { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.FOR,lexer.getLineNumber()+1);
                                  $$.addChild($3); $$.addChild($5); printDebug("for"); }
        ;

for_condition: for_cond_sec1 for_cond_sec2 assignment
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.FORCOND,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($2); $$.addChild($3); }
        | for_cond_sec1 for_cond_sec2
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.FORCOND,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($2);
                                  $$.addChild(new SyntaxTreeNode(null, SyntaxTreeNode.Type.NONE,lexer.getLineNumber()+1)); }
        ;

for_cond_sec1: assignment ';'   { $$ = $1; }
        | ';'                   { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.NONE,lexer.getLineNumber()+1); }
        ;

for_cond_sec2: expression ';'   { $$ = $1; }
        | ';'                   { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.NONE,lexer.getLineNumber()+1); }
        ;

/* used in customer-defined function only */
func_keyword_statement: return  { $$ = $1; }
        | CONTINUE              { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.CONTINUE,lexer.getLineNumber()+1); }
        | BREAK                 { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.BREAK,lexer.getLineNumber()+1); }
        | print                 { $$ = $1; }
        ;

return: RETURN                  { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.RETURN,lexer.getLineNumber()+1); }
        | RETURN expression     { $$ = new SyntaxTreeNode(null, SyntaxTreeNode.Type.RETURN,lexer.getLineNumber()+1);
                                  $$.addChild($2); }
        ;

list: list ',' object           { $$ = $1; $$.addChild($3); }
        | object                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode("LIST",SyntaxTreeNode.Type.LIST,lexer.getLineNumber()+1); $$.addChild(tmp); }
        ;

cond:  cond LOGICAL cond        { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode($2,SyntaxTreeNode.Type.LOGICAL,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3);}
        | object compare object { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode($2,SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild(tmp); $$.addChild($3);}
        | indicator CROSSOP indicator
                                { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode($2,SyntaxTreeNode.Type.CROSSOP,lexer.getLineNumber()+1); $$.addChild(tmp); $$.addChild($3);}
        | TF                    { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.TF,lexer.getLineNumber()+1); }
        | '(' cond ')'          { $$ = $2; }
        | NOT cond              { $$ = new SyntaxTreeNode($1, SyntaxTreeNode.Type.LOGICAL,lexer.getLineNumber()+1);
                                  $$.addChild($2); }
        ;

/* expression used only in user-defined function */
expression: single_cond LOGICAL expression
                                { SyntaxTreeNode tmp = $1; 
                                  $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.LOGICAL,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3); }
        | NOT expression        { $$ = new SyntaxTreeNode($1, SyntaxTreeNode.Type.LOGICAL,lexer.getLineNumber()+1); 
                                  $$.addChild($2); }
        | single_cond           { $$ = $1; }
        ;

single_cond : expr compare single_cond
                                { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3); }
     | expr                     { $$ = $1; }
     ;

expr : atom arith_operator expr { SyntaxTreeNode tmp = $1;
                                  $$ = new SyntaxTreeNode($2, SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1);
                                  $$.addChild(tmp); $$.addChild($3); }
     | '-' expr %prec NEG       { $$ = new SyntaxTreeNode("NEG", SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1);
                                  $$.addChild($2);} 
     | atom                     { $$ = $1; }
     ;

object: LITSTRING               { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.LITSTRING,lexer.getLineNumber()+1);}
      | identifier              { $$ = $1;}
      | exp                     { $$ = $1;}
      | TF                      { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.TF,lexer.getLineNumber()+1);}
      ;

atom:  number                   { $$ = $1; }
        | identifier            { $$ = $1; }
        | function              { $$ = $1; }
        | indicator             { $$ = $1; }
        | predefined_id         { $$ = $1; }
        | TF                    { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.TF,lexer.getLineNumber()+1);}
        | LITSTRING             { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.LITSTRING,lexer.getLineNumber()+1);}
        | '(' expression ')'    { $$ = $2; }
        ;

/* expression in strategies - we can consider use expr and do type check */
exp:  number                    { $$ = $1; }
       | function               { $$ = $1; }
       | indicator              { $$ = $1; }
       | predefined_id          { $$ = $1; }
       | exp '+' exp            { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode("+",SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild(tmp);$$.addChild($3); }
       | exp '-' exp            { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode("-",SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild(tmp);$$.addChild($3); }
       | exp '*' exp            { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode("*",SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild(tmp);$$.addChild($3); }
       | exp '/' exp            { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode("/",SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild(tmp);$$.addChild($3); }
       | '-' exp  %prec NEG     { $$ = new SyntaxTreeNode("NEG",SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild($2); }
       | exp '^' exp            { SyntaxTreeNode tmp = $1; $$ = new SyntaxTreeNode("^",SyntaxTreeNode.Type.OP,lexer.getLineNumber()+1); $$.addChild(tmp);$$.addChild($3); }
       | '(' exp ')'            { $$ = $2; }
       ;

arith_operator: '+'             { $$ = "+"; }
        | '-'                   { $$ = "-"; }
        | '*'                   { $$ = "*"; }
        | '/'                   { $$ = "/"; }
        | '^'                   { $$ = "^"; }
        ;

predefined_id: VOLUME           { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        | PRICE                 { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        | SECTOR                { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        | LOSS                  { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        | PROFIT                { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        | RISE                  { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        | FALL                  { $$ = new SyntaxTreeNode($1,SyntaxTreeNode.Type.PREDEFINED,lexer.getLineNumber()+1);}
        ;

identifier: IDENT               { $$=new SyntaxTreeNode($1,SyntaxTreeNode.Type.ID,lexer.getLineNumber()+1); }
        | IDENT '.' IDENT       { $$=new SyntaxTreeNode($1+"."+$3,SyntaxTreeNode.Type.ID,lexer.getLineNumber()+1); }
        ;

indicator: CAPIDENT '(' list ')'
                                { $$=new SyntaxTreeNode($1,SyntaxTreeNode.Type.INDICATOR,lexer.getLineNumber()+1);$$.addChild($3);}
        | CAPIDENT '(' ')'      { $$=new SyntaxTreeNode($1,SyntaxTreeNode.Type.INDICATOR,lexer.getLineNumber()+1);}
        ;

function: identifier '(' list ')'
                                { $$=new SyntaxTreeNode($1,SyntaxTreeNode.Type.FUNC,lexer.getLineNumber()+1);$$.addChild($3);}
        | identifier '(' ')'    { $$=new SyntaxTreeNode($1,SyntaxTreeNode.Type.FUNC,lexer.getLineNumber()+1);}
        ;

action:    BUY                  { $$=new SyntaxTreeNode(null,SyntaxTreeNode.Type.BUY,lexer.getLineNumber()+1); }
       |   BUY INTEGER          { $$=new SyntaxTreeNode($2,SyntaxTreeNode.Type.BUY,lexer.getLineNumber()+1); }
       |   SELL                 { $$=new SyntaxTreeNode(null,SyntaxTreeNode.Type.SELL,lexer.getLineNumber()+1);}
       |   SELL INTEGER         { $$=new SyntaxTreeNode($2,SyntaxTreeNode.Type.SELL,lexer.getLineNumber()+1);}
       ;

compare: EQ                     { $$="==";}
       | '<'                    { $$="<";}
       | '>'                    { $$=">";}
       | NEQ                    { $$="!=";}
       | GEQ                    { $$=">=";}
       | LEQ                    { $$="<=";}
       ;

number: INTEGER                 { $$ = new SyntaxTreeNode($1, SyntaxTreeNode.Type.INT,lexer.getLineNumber()+1);}
      | NUM                     { $$ = new SyntaxTreeNode($1, SyntaxTreeNode.Type.NUM,lexer.getLineNumber()+1);}
      | PERCENT                 { $$ = new SyntaxTreeNode($1, SyntaxTreeNode.Type.NUM,lexer.getLineNumber()+1);}
      ;

%%

  private Lexer lexer;
  public SyntaxTreeNode root;
  private Boolean debugFlag = false;
  private int debugLevel = 1;
  
  public static final class Semantic{
          public int ival;
        public double dval;
        public String sval;
        public SyntaxTreeNode node;
        
        public Semantic()
        {
        }
        public Semantic(Semantic sem)
        {
                ival=sem.ival;
                dval=sem.dval;
                sval=sem.sval;
                node=sem.node;
        }
        public Semantic(int val)
        {
                ival = val;
        }
        public Semantic(double val)
        {
                dval = val;
        }
        public Semantic(String val)
        {
                sval = val;
        }
        public Semantic(SyntaxTreeNode val)
        {
                node = val;
        }
  }

  public int parse() throws CompileError {
  	return yyparse();
  }

  private int yylex () {
    int yyl_return = -1;
    try {
      yylval = new Semantic(0);
      yyl_return = lexer.yylex();
    }
    catch (IOException e) {
      System.err.println("IO error :"+e);
    }
    return yyl_return;
  }


  public void yyerror (String error) throws CompileError{
      throw new CompileError(error, lexer.getLineNumber() + 1);
  }


  public Parser(Reader r) {
    lexer = new Lexer(r, this);
  }

  public void printDebug(String s) {
          if (debugFlag) {
                System.out.println(s);
        }
  }

  public void printDebug(String s, int level) {
        if (level > debugLevel) {
                System.out.println(s);
        }
  }

  static boolean interactive;

  public static void main(String args[]) throws IOException, CompileError {
    System.out.println("DayTrader Interpreter!");

    Parser yyparser;
    if ( args.length > 0 ) {
      // parse a file
      yyparser = new Parser(new FileReader(args[0]));
    }
    else {
      // interactive mode
      System.out.println("[Quit with CTRL-D]");
      System.out.print("> ");
      interactive = true;
      yyparser = new Parser(new InputStreamReader(System.in));
    }

    yyparser.yyparse();
    
    if (interactive) {
      System.out.println();
      System.out.println("Bye!");
    }
  }
